﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Engine.Objects;

namespace Editor
{
    class Editor : Engine.NOWAEngine
    {
        VertexBuffer geometryBuffer;
        IndexBuffer indexBuffer;
        VertexDeclaration vertexDeclaration;
        Effect effect;
        VertexElement[] streamElements;
        Matrix view;
        Matrix projection;
        int count = 65000;
        VertexBuffer instanceBuffer;

        struct InstanceInfo
        {
            public Matrix World;
            public Vector4 Color;

           
        };
        public Editor()
        {

        }
        public Editor(IntPtr hndl, IntPtr hndlp)
            : base(hndl, hndlp)
        {
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            GenerateBuffers();
            GenerateStreamElements();
            GenerateInstanceInformation();

            effect = Content.Load<Effect>("Hinstance");
            view = Matrix.CreateLookAt(new Vector3(150, 150, 150), Vector3.Zero, Vector3.UnitZ);
            projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)Window.ClientBounds.Width / (float)Window.ClientBounds.Height, 0.1f, 2000.0f);
        }

        protected override void UnloadContent()
        {
        }

        private void GenerateBuffers()
        {
            VertexPositionColor[] vertices = new VertexPositionColor[6];
            vertices[0].Position = new Vector3(-1, 0, -1);
            vertices[0].Color = Color.Red;
            vertices[1].Position = new Vector3(1, 0, -1);
            vertices[1].Color = Color.Green;
            vertices[2].Position = new Vector3(0, 0, 1);
            vertices[2].Color = Color.Blue;
            vertices[3].Position = new Vector3(-1, 1, -1);
            vertices[3].Color = Color.Red;
            vertices[4].Position = new Vector3(1, 1, -1);
            vertices[4].Color = Color.Green;
            vertices[5].Position = new Vector3(0, 1, 1);
            vertices[5].Color = Color.Blue;
            geometryBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), 6, BufferUsage.WriteOnly);
            geometryBuffer.SetData(vertices);

            short[] indices = new short[24];
            indices[0] = 1; indices[1] = 3; indices[2] = 0;
            indices[3] = 4; indices[4] = 3; indices[5] = 1;
            indices[6] = 2; indices[7] = 4; indices[8] = 1;
            indices[9] = 5; indices[10] = 4; indices[11] = 2;
            indices[12] = 5; indices[13] = 2; indices[14] = 0;
            indices[15] = 3; indices[16] = 5; indices[17] = 0;
            indices[18] = 2; indices[19] = 1; indices[20] = 0;
            indices[21] = 5; indices[22] = 3; indices[23] = 4;
            indexBuffer = new IndexBuffer(GraphicsDevice, typeof(short), 24, BufferUsage.WriteOnly);
            indexBuffer.SetData(indices);
        }

        private void GenerateStreamElements()
        {
            streamElements = new VertexElement[7];
            streamElements[0] = new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0);
            streamElements[1] = new VertexElement(sizeof(float) * 3, VertexElementFormat.Color, VertexElementUsage.Color, 0);
            streamElements[2] = new VertexElement(sizeof(float) * 4, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 0);
            streamElements[3] = new VertexElement(sizeof(float) * 8, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 1);
            streamElements[4] = new VertexElement(sizeof(float) * 12, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 2);
            streamElements[5] = new VertexElement(sizeof(float) * 16, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 3);
            streamElements[6] = new VertexElement(sizeof(float) * 20, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 4);
            vertexDeclaration = new VertexDeclaration(streamElements);
        }

        private void GenerateInstanceInformation()
        {
            InstanceInfo[] instances = new InstanceInfo[count];
            Random rnd = new Random();
            for (int i = 0; i < count; i++)
            {
                instances[i].World = Matrix.CreateTranslation(new Vector3(-rnd.Next(200), -rnd.Next(300), -rnd.Next(150)));
                instances[i].Color = new Vector4((float)rnd.NextDouble(), (float)rnd.NextDouble(), (float)rnd.NextDouble(), 1);
            }
            
            instanceBuffer = new VertexBuffer(GraphicsDevice, vertexDeclaration, count, BufferUsage.WriteOnly);
            instanceBuffer.SetData(instances);
        }

        protected override void Update(GameTime gameTime)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                this.Exit();

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.White);
            //GraphicsDevice.VertexDeclaration = vertexDeclaration;
            effect.CurrentTechnique = effect.Techniques["Instancing"];
            DEFAULTCamera cam = (DEFAULTCamera)(Manager.GetComponent("CameraManager")).GetMaincamera();

            view = cam.ViewMatrix;
            projection = cam.ProjectionMatrix;
            effect.Parameters["WVP"].SetValue(view * projection);
            GraphicsDevice.Indices = indexBuffer;
            //effect.Begin();
            foreach (EffectPass p in effect.CurrentTechnique.Passes)
            {
                p.Apply();
                GraphicsDevice.SetVertexBuffers(geometryBuffer, new VertexBufferBinding(instanceBuffer,0,1));
                GraphicsDevice.SetVertexBuffer(instanceBuffer, 1);

                GraphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, geometryBuffer.VertexCount, 0, indexBuffer.IndexCount / 3, instanceBuffer.VertexCount);
                //p.End();
            }

            base.Draw(gameTime);
        }
    }
}

